home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-07-05 | 67.5 KB | 2,797 lines | [TEXT/R*ch] |
- // DGopher.cp
- // by d.g. gilbert, Mar 1992
- // version for DClap, Jan 94
- /*
- This code is Copyright (C) 1992 by D.G. Gilbert.
- All Rights Reserved.
-
- You may use this code for your personal use, to provide a non-profit
- service to others, or to use as a test platform for a commercial
- implementation.
-
- You may not use this code in a commercial product, nor to provide a
- commercial service, nor may you sell this code without express
- written permission of the author.
-
- gilbertd@bio.indiana.edu
- Biology Dept., Indiana University, Bloomington, IN 47405
- */
-
-
- #include <ncbi.h>
- #include <dgg.h>
-
- #include "DTCP.h"
- #include "DURL.h"
- #include "DGopher.h"
- #include "DGoList.h"
- #include "DGoPlus.h"
- #include "DGoInit.h"
- #include "DGoClasses.h"
-
- #include <DFile.h>
- #include <DList.h>
- #include <DIconLib.h>
- #include <DView.h>
- #include <DChildApp.h>
-
-
- enum commonTCPports {
- kUnknownPort = 0,
- kUnsupportedPort = 0,
- kFileport = 21,
- kFTPport = 21,
- kSMTPport = 25,
- kTelnetport = 23,
- kTN3270port = 23,
- kWhoisport= 43,
- kGopherport = 70,
- kFingerport = 79,
- kHTTPport = 80,
- kPOPport = 110,
- kNNTPport = 119,
- kWAISport = 210
- };
-
- //public variables
- //Global const short kGopherPort = 70; // default/prime port #
-
- Global const long kReadMaxbuf = 1024;
-
- Global DIconList* gGopherIcons = NULL;
- Global short gGopherIconID;
- Global short gIconSize;
-
- Global Boolean gUseDigFolder;
- Global short gDigVol;
- Global long gDigDirID;
-
- Global Boolean gShortFolder = false;
- Global Boolean gListUnknowns = false;
- Global Boolean gDoSuffix2MacMap = false; // !?? started bombing 26Dec94 w/ this != false
-
-
- #if !defined(OS_MAC) && !defined(OS_UNIX) && !defined(OS_DOS) && !defined(OS_VMS)
- Global char * gLocalGopherRoot = "";
- Global char * gAskWaisPath = "";
- #endif
- #ifdef OS_MAC
- Global char * gLocalGopherRoot = ":";
- Global char * gAskWaisPath = ":bin:askwais";
- #endif
- #ifdef OS_UNIX
- Global char * gLocalGopherRoot = ".";
- Global char * gAskWaisPath = "/bin/askwais";
- #endif
- #if defined(OS_DOS) || defined (OS_NT)
- Global char * gLocalGopherRoot = ".";
- Global char * gAskWaisPath = "\bin\askwais";
- #endif
- #ifdef OS_VMS
- // damn, what is vms syntax for local subdir ??
- Global char * gLocalGopherRoot = "[Gopher-root]";
- Global char * gAskWaisPath = "[bin]askwais.exe";
- #endif
-
-
- //private variables
-
- //Local DGopher *gCurrentGopher;
-
- Local const char* gEmptyString = "";
- Local const char* kDefaultLink = "1Title of gopher link\t\tHost.Name.Goes.Here\t70";
- Local const char* kLocalhost = "localhost";
-
- Local const long kReadToClose = DTCP::kTCPStopAtclose;
- Local const long kReadToDotCRLF = DTCP::kTCPStopAtdotcrlf;
-
- Local const long kReadMaxbuf1 = 1 * 1024;
- Local const long kMaxInt = 32000;
-
- Local const char *gMonths[13] =
- {"Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec","???"};
-
-
-
- // DGopherTalk ------------------------------
-
-
- DGopherTalk::DGopherTalk(): DTCP()
- {
- fLinesRead= 0;
- NullTerm(false);
- //InstallMessageLine( aStatusLine);
- }
-
-
-
- void DGopherTalk::OpenQuery( char* host, short port, char* path, char* query,
- char* viewchoice, char* plus, DFile* plusFile)
- {
- void *crlfdotcrlf = (void*) CRLF"."CRLF; //"\015\012";
-
- ShowMessage("TCP opening connection to host");
- Open((char*)host, port);
- if (Failed()) return;
- if (!WaitedForOpen(0)) return;
- if (path) Send( path, kDontSendNow);
- if (query) Send( query, kDontSendNow);
- if (viewchoice) Send( viewchoice, kDontSendNow);
-
- if (!plus) {
- SendBytes(crlfdotcrlf, 5, kSendNow); // send dot-cr-lf
- }
-
- else {
- // if (plus) send plus data header, form depends on plusFile:
- //char *header0 = "\t+\t1\n\r+NBYTES\n\r";
- //char *header1 = "\t+\t1\n\r+-1\n\r";
- //char *header2 = "\t+\t1\n\r+-2\n\r";
-
- if (!plusFile) {
- if (StrChr(plus, kCR)) { // more than one line in plus == ASK block
- char header[80];
- //long len = strlen(plus);
- //sprintf( header, "\t+\t1\n\r+%d\n\r", len); // exactly <len> bytes of data
- // ^^ this isn't understood by server ?!?
- #if 1
- // 1apr94 fix for bad DGoFolder selectors
- // bad: path|+view|+|1<cr>ask data
- // good: path|+view|1<cr>data or path|$|1<cr>data or path|+|1<cr>data
- char* selector= (viewchoice) ? "" : "\t$"; // or "+";
- sprintf( header, "%s\t1"CRLF"+-1"CRLF, selector); // data until dot-cr-lf
- #else
- sprintf( header, "\t+\t1"CRLF"+-1"CRLF); // data until dot-cr-lf
- #endif
- Send( header, kDontSendNow);
- Send( plus, kDontSendNow);
- SendBytes(crlfdotcrlf, 5, kSendNow);
- }
- else {
- Send( plus, kDontSendNow);
- SendBytes(crlfdotcrlf, 5, kSendNow);
- }
- }
-
- else { //if (plusFile)
- const short kMaxBuf = 2048;
- char buffer[kMaxBuf];
- short err;
- Boolean fullbuf, done= false;
- long fileType = cTEXT;
- ulong count, lenFile, fat = 0;
-
- err = plusFile->OpenFile();
- err |= plusFile->GetDataLength( lenFile);
- err |= plusFile->GetFileType( fileType);
-
- if (fileType == cTEXT) {
- /// ARrrrgggghhhh -- need to do newline translation here (at least if type==TEXT)
- char header[80];
- sprintf( header, "\t+\t1"CRLF"+-1"CRLF); // data until dot-cr-lf
- Send( header, kDontSendNow);
- Send( plus, kDontSendNow);
- SendCRLF(false, kDontSendNow); // ensure newline
- while (! (done || err)) {
- count= kMaxBuf;
- err |= plusFile->ReadUntil( buffer, count, *LineEnd);
- fullbuf = (count+2 > kMaxBuf);
- if (buffer[count-1] == kCR) {
- if (fullbuf) count--;
- else buffer[count++]= kLF; // add lf;
- }
- else {
- if (!fullbuf) {
- buffer[count++]= kCR;
- buffer[count++]= kLF;
- }
- }
- if (count==3 && 0==memcmp(buffer, "."CRLF, 3))
- this->SendBytes(".."CRLF, 4, kDontSendNow); // make sure we don't send terminator by mistake
- else
- this->SendBytes(buffer, count, kSendNow); //kDontSendNow
- if (fullbuf) this->SendCRLF(kDontSendNow);
-
- err |= plusFile->GetDataMark(fat);
- done|= fat >= lenFile;
- }
- SendCRLF(false, kDontSendNow); // ensure newline
- SendBytes("."CRLF, 3, kSendNow); // send dot-cr-lf
- }
-
- else {
- char header[80];
- long len = strlen(plus) + lenFile;
- //sprintf( header, "\t+\t1"CRLF"+%d"CRLF, len); // exactly <len> bytes of data
- // ^^ this isn't understood by server ?!?
- sprintf( header, "\t+\t1"CRLF"+-2"CRLF); // data until close
- Send( header, kDontSendNow);
- Send( plus, kDontSendNow);
- //SendCRLF(false, kDontSendNow); // ??! ensure newline -- not w/ fixed bytecount...
- while (! (done || err)) {
- count= kMaxBuf;
- err |= plusFile->ReadData( buffer, count);
- this->SendBytes(buffer, count, kSendNow);
- err |= plusFile->GetDataMark(fat);
- done|= fat >= lenFile;
- }
- }
-
- err= plusFile->CloseFile();
- }
- }
-
- // long ticktock= TickCount() + fTimeout;
- // while (!CharsAvailable() && TickCount() < ticktock && !UserBreak() )
- // StatusMessage();
- SetShowProgress( true);
-
- }
-
-
-
-
- Boolean DGopherTalk::ReadALine( CharPtr appendToHandle, CharPtr& result)
- {
- result= NULL;
- fResultNew= 0;
- CharPtr data= RecvLine(); //RecvUpTo( true, kLF, NULL); // includes lf+null at end
- //- fEndofMessage= false; << !?! RecvUpTo NO LONGER sets this true at Linefeed ?
- Boolean readone= (data!=NULL);
- fLinesRead++;
- if (readone) {
- if ( data[0] == '.' && data[1] == kCR) fEndofMessage= true;
- // ^^ this changes w/ subclasses...
-
- // some damn terminator patching -- always end string w/ Return, no lf or null
- long len= StrLen(CharPtr(data));
- //len--; //drop null, always there from RecvUpTo() << NO,
- //if (len < kMaxInt) << do we need to stop at 32K ??
- {
- if ( data[len-1] == kLF) len--;
- if ( data[len-1] != kCR) data[len++]= *LineEnd;
- }
- data= (char*) MemMore( data, Max(0,len));
-
- if (appendToHandle == NULL)
- appendToHandle= data;
- else {
- long oldlen= StrLen(appendToHandle);
- appendToHandle= (char*)MemMore( appendToHandle, oldlen+len+1);
- MemCopy( appendToHandle+oldlen, data, len);
- appendToHandle[oldlen+len]= 0;
- }
- }
- result= appendToHandle;
- return readone;
- }
-
-
-
-
-
-
- // DocLink ------------------------------
-
-
- DocLink::DocLink() :
- fType(kNoLink), fParag(0), fChar(0)
- {
- string.fString= NULL;
- }
-
- DocLink::~DocLink()
- {
- if (fType == kString) MemFree( string.fString);
- }
-
- void DocLink::Clear()
- {
- if (fType == kString) MemFree( string.fString);
- fType= kNoLink;
- }
-
- void DocLink::DupData()
- {
- if (fType == kString)
- string.fString= StrDup( string.fString);
- }
-
- char * DocLink::GetString( short& skipval)
- {
- skipval= string.fSkip;
- return string.fString;
- }
-
- void DocLink::SetString( const char* thestr, short skipvalue)
- {
- Clear();
- fType= kString;
- string.fString= StrDup(thestr);
- string.fSkip= skipvalue;
- }
-
- void DocLink::SetSkip( short skipvalue)
- {
- if (fType == kString) string.fSkip= skipvalue;
- }
-
- void DocLink::SetRect( Nlm_RecT therect)
- {
- Clear();
- fType= kRect;
- rect.fRect= therect;
- }
-
- void DocLink::GetLine( short& atparag, short& atchar, short& endparag, short& endchar )
- {
- atparag= fParag;
- atchar= fChar;
- endparag= line.fEndParag;
- endchar= line.fEndChar;
- }
-
- void DocLink::SetLine( short atparag, short atchar, short endparag, short endchar )
- {
- Clear();
- fType= kLine;
- fParag= atparag;
- fChar= atchar;
- line.fEndParag= endparag;
- line.fEndChar= endchar;
- }
-
- void DocLink::GetLineRect( Nlm_RecT& therect, short& atparag, short& atchar )
- {
- therect= rect.fRect;
- atparag= fParag;
- atchar= fChar;
- }
-
- void DocLink::SetLineRect( Nlm_RecT therect, short atparag, short atchar)
- {
- Clear();
- fType= kLineRect;
- fParag= atparag;
- fChar= atchar;
- rect.fRect= therect;
- }
-
-
-
-
-
- // DGopherAbstract ------------------------------
-
- class DGopherAbstract : public DObject
- {
- public:
- short fLines;
- long fSize;
- char* fText;
-
- DGopherAbstract( char* text);
- ~DGopherAbstract() { Clear(); }
-
- virtual DObject* Clone();
- void Set( const char* text);
- void Clear();
- void Install( const char* text) { Clear(); Set( text); }
- void Draw( Nlm_RecT& area);
- short Height();
- };
-
- DGopherAbstract::DGopherAbstract( char* text) :
- fLines(0), fSize(0), fText(NULL)
- {
- Set( text);
- }
-
- void DGopherAbstract::Clear()
- {
- MemFree( fText);
- fSize= fLines= 0;
- }
-
- DObject* DGopherAbstract::Clone()
- {
- DGopherAbstract* myClone= (DGopherAbstract*) DObject::Clone();
- myClone->fText= StrDup(fText);
- return myClone;
- }
-
- void DGopherAbstract::Set( const char* text)
- {
- char *cp, *dp, c, lastc;
- Boolean havevis= false;
- long bytes= StringLen( text);
- if (bytes>0) {
- fText= (char*) MemNew( bytes+1);
- fLines= 1;
- for (cp= (char*)text, dp= fText, lastc= 0; *cp != 0; cp++) {
- c= *cp;
- if (c == kCR) {
- if (havevis) { *dp++= NEWLINE; fLines++; }
- }
- else if (c == kLF) {
- if (lastc == kCR) ; // eat c
- else if (havevis) { *dp++= NEWLINE; fLines++; }
- }
- else if (havevis) *dp++= c;
- else { havevis= isgraph(c); if (havevis) *dp++= c; }
- lastc= c;
- }
- while ( fLines && dp > fText && dp[-1] == NEWLINE) {
- // drop trailing blank lines
- fLines--; dp--;
- }
- *dp= 0;
- fSize= dp - fText;
- }
- }
-
- void DGopherAbstract::Draw( Nlm_RecT& area)
- {
- if (fText) {
- //? Nlm_DrawString(&area, fText, 'l', false);
- Dgg_DrawTextbox( &area, fText, fSize, 'l', false);
- }
- }
-
- short DGopherAbstract::Height()
- {
- if (fLines)
- return (fLines * Nlm_LineHeight());
- else
- return 0;
- }
-
-
-
-
-
-
-
-
-
- // DGopher ------------------------------
-
-
- DGopher::DGopher( char ctype, const char* link) :
- DTaskMaster( 0, NULL, NULL)
- {
- Initialize();
- SetLink( ctype, link);
- }
-
- DGopher::DGopher() :
- DTaskMaster( 0, NULL, NULL)
- {
- Initialize();
- SetLink( *kDefaultLink, kDefaultLink);
- }
-
- DGopher::DGopher( DGopher* aGopher) :
- DTaskMaster( 0, NULL, NULL)
- {
- Initialize();
- CopyGopher( aGopher);
- }
-
-
- DGopher::~DGopher()
- {
- DeleteLink(false);
- fInfo= (char*) MemFree( fInfo);
- }
-
- Boolean DGopher::suicide(void)
- {
- if (GetOwnerCount() <= 1) {
- delete this;
- return true;
- }
- else
- return DObject::suicide();
- }
-
- Boolean DGopher::suicide(short ownercount)
- {
- if (ownercount < 1) {
- delete this;
- return true;
- }
- else
- return DObject::suicide(ownercount);
- }
-
- DObject* DGopher::Clone()
- {
- //DGopher* aGopher= (DGopher*)DObject::Clone();
- DGopher* aGopher= new DGopher();
- aGopher->CopyGopher( this);
- return aGopher;
- }
-
-
-
- void DGopher::Initialize()
- {
- fLink= NULL;
- fLinkLen= 0;
- fItitle= 0;
- fIdate = 0;
- fIsize = 0;
- fIpath = 0;
- fIhost = 0;
- fIport = 0;
- fIplus = 0;
-
- fType = kTypeError; //== ancestor doesn't know much...
- fProtocol = kGopherprot;
- fIsLocal= false;
- fPort = kGopherport;
- fURL= NULL;
- fDate= NULL; fDateLong= 0;
- fDataSize= NULL; fSizeLong= 0;
- fInfo= NULL;
- fInfoSize= 0;
- fInfoHandler= NULL;
-
- fOwnerList= NULL;
- fStatusLine= NULL;
-
- fDeleted= false;
- fInUseCount= 1;
- fTalker= NULL;
- fMacType= cTEXT;
- fMacSire= cEDIT;
- fTransferType= kTransferText; //text/lines or binary or none ?
- fSaveToDisk= false;
- fLaunch= false;
- fQuery= NULL;
- fQueryGiven= NULL;
- #if 1
- fDocLink= NULL; //ClearDocLink();
- #else
- fMenuString= NULL;
- fMenuStringSkip= 0;
- fDocLinkParag= 0;
- fDocLinkChar= 0;
- fDocLinkLen= 0;
- #endif
-
- fCommand= cNoCommand;
- fThreadState= kThreadNotStarted;
- fBytesExpected= 0;
- fBytesReceived= 0;
- fConnectTime= 0;
- fAppFile= NULL;
-
- // gopher+
- fShortFolder= gShortFolder; //false;
- fHasAsk= false;
- fIsMap= false;
- fHaveReply= false;
- fReplyFile= NULL;
- fReplyData= NULL;
- fIsPlus= kGopherPlusDontKnow;
- fQueryPlus= NULL;
- fAdminEmail= NULL;
- fViews= NULL; // list of CGopherItemView
- fViewchoice= 0;
- fAskers = NULL;
- fAbstract= NULL;
- fGoMenuBlock= NULL;
- fInfo = (char*)Nlm_MemGet(1, true);
- fInfoSize= 0; // fInfoSize is size of data not including terminating NULL !@!@$#@#
- }
-
- void DGopher::CopyGopher( DGopher* aGopher)
- {
- if (aGopher) {
- // This memcpy was bad...problem was NULL aGopher !!!
- //memcpy(&fType, &aGopher->fType, sizeof(DGopher)); //<< bad for subclass w/ larger size !
-
- fType = aGopher->fType;
- fItitle = aGopher->fItitle;
- fIdate = aGopher->fIdate;
- fIsize = aGopher->fIsize;
- fIpath = aGopher->fIpath;
- fIhost = aGopher->fIhost;
- fIport = aGopher->fIport;
- fIplus = aGopher->fIplus;
- fPort = aGopher->fPort;
- fLink = (char*) MemDup( aGopher->fLink, aGopher->fLinkLen);
- fLinkLen= aGopher->fLinkLen;
-
- fDate = (char*) StrDup( (CharPtr)aGopher->fDate);
- fDateLong = aGopher->fDateLong;
- fDataSize = (char*) StrDup( (CharPtr)aGopher->fDataSize);
- fSizeLong = aGopher->fSizeLong;
-
- fAdminEmail= (char*) StrDup( (CharPtr)aGopher->fAdminEmail);
- fViews = aGopher->CloneViews();
- fAskers = aGopher->CloneAskers();
- if (aGopher->fAbstract) fAbstract = (DGopherAbstract*) aGopher->Clone();
- fIsPlus = aGopher->fIsPlus;
- fShortFolder = aGopher->fShortFolder;
- fHasAsk = aGopher->fHasAsk;
- fHaveReply = aGopher->fHaveReply;
- if (aGopher->fReplyFile) fReplyFile = (DFile*) aGopher->fReplyFile->Clone();
- fReplyData = StrDup( aGopher->fReplyData);
- if (aGopher->fGoMenuBlock) fGoMenuBlock= new DGoMenuBlock(this, aGopher->fGoMenuBlock->fData);
- else fGoMenuBlock= NULL;
-
- fProtocol= aGopher->fProtocol;
- fURL = (char*) StrDup( (CharPtr)aGopher->fURL);
- fIsLocal= aGopher->fIsLocal;
- fIsMap = aGopher->fIsMap;
-
- MemFree( fInfo);
- fInfoSize= aGopher->fInfoSize;
- fInfo= (char*)MemDup( aGopher->fInfo, fInfoSize+1);
- fInfoHandler= aGopher->fInfoHandler; //??
-
- fQuery = aGopher->fQuery;
- fQueryPlus = aGopher->fQueryPlus;
- fQueryGiven = StrDup( aGopher->fQueryGiven);
-
- //fTransferType = aGopher->fTransferType;
- //fDeleted= false;
- //fMacType = aGopher->fMacType; // PRESERVE for CopyToNewKind
- //fMacSire = aGopher->fMacSire; // PRESERVE for CopyToNewKind
- //fSaveToDisk = aGopher->fSaveToDisk; // PRESERVE for CopyToNewKind
- //fLaunch = aGopher->fLaunch; // PRESERVE for CopyToNewKind
- //fCommand = aGopher->fCommand; // PRESERVE for CopyToNewKind
- //fViewchoice = aGopher->fViewchoice; // PRESERVE for CopyToNewKind
- //fOwnerList= NULL; //!?
- fStatusLine= aGopher->fStatusLine;
- //fTalker= NULL; //?
- fBytesExpected= aGopher->fBytesExpected;
- //fBytesReceived= aGopher->fBytesReceived;
- //fConnectTime= aGopher->fConnectTime;
- //fThreadState= aGopher->fThreadState;
- //fAppFile = NULL; //??
- //fInUseCount= 1;
- fDocLink= aGopher->fDocLink;
- if (fDocLink) fDocLink->DupData();
- }
- }
-
- void DGopher::DeleteInfo()
- {
- if (fInfo) fInfo= (char*) MemMore( fInfo, 1);
- else fInfo= (char*) MemNew(1);
- *fInfo= 0;
- fInfoSize= 0;
- }
-
- void DGopher::DeleteViews()
- {
- if (fViews) {
- fViews->FreeAllObjects();
- fViews->suicide();
- fViews= NULL;
- }
- }
-
- DList* DGopher::CloneViews()
- {
- DList* newViews= NULL;
- if (fViews) {
- newViews= new DList();
- long i, n= fViews->GetSize();
- for (i= 0; i<n; i++) newViews->InsertLast( fViews->At(i)->Clone());
- }
- return newViews;
- }
-
-
- void DGopher::DeleteAskers()
- {
- if (fAskers) {
- fAskers->FreeAllObjects();
- fAskers->suicide();
- fAskers= NULL;
- }
- }
-
- DList* DGopher::CloneAskers()
- {
- DList* newAskers= NULL;
- if (fAskers) {
- newAskers= new DList();
- long i, n= fAskers->GetSize();
- for (i= 0; i<n; i++) newAskers->InsertLast( fAskers->At(i)->Clone());
-
- }
- return newAskers;
- }
-
-
-
- void DGopher::DeleteLink(Boolean onlyInfoline)
- {
- fLink = (char*) MemFree( fLink);
- fLinkLen= 0;
- // zero the indices into flink
- fItitle = fIdate= fIsize= fIpath= fIhost= fIport= fIplus = 0;
-
- if (!onlyInfoline) {
- if (fDate) fDate = (char*)MemFree( (CharPtr)fDate);
- if (fDataSize) fDataSize= (char*)MemFree( (CharPtr)fDataSize);
- if (fAppFile) fAppFile= (char*)MemFree( fAppFile);
- if (fAdminEmail) fAdminEmail = (char*)MemFree( (CharPtr)fAdminEmail);
- if (fGoMenuBlock) { delete fGoMenuBlock; fGoMenuBlock= NULL; }
- if (fAbstract) { delete fAbstract; fAbstract= NULL; }
- if (fQueryGiven) fQueryGiven= (char*)MemFree( fQueryGiven);
- #if 1
- if (fDocLink) delete fDocLink; fDocLink= NULL;
- #else
- if (fMenuString) fMenuString= (char*)MemFree( fMenuString);
- #endif
-
- DeleteViews();
- DeleteAskers();
- }
- }
-
-
-
-
- Boolean DGopher::HasDocLink()
- {
- return (fDocLink && fDocLink->HasLink());
- //return (fDocLinkParag || fDocLinkChar || fDocLinkLen);
- }
-
- #if 0
- void DGopher::GetDocLink( short& atParagraph, short& atChar, short& length)
- {
- atParagraph= fDocLinkParag;
- atChar= fDocLinkChar;
- length= fDocLinkLen;
- }
-
- void DGopher::SetDocLink( short atParagraph, short atChar, short length)
- {
- fDocLinkParag= atParagraph;
- fDocLinkChar= atChar;
- fDocLinkLen= length;
- }
-
- void DGopher::ClearDocLink()
- {
- fDocLinkParag= 0;
- fDocLinkChar= 0;
- fDocLinkLen= 0;
- }
- #endif
-
-
-
- void DGopher::AddView( const char* viewkind)
- {
- if (!fViews) fViews = new DList();
- DGopherItemView* giv= new DGopherItemView( viewkind);
- fViews->InsertLast( giv);
- }
-
-
- void DGopher::SetPlusInfo( short isPlus, Boolean hasAsk, char* plus)
- {
- char *cp, *ep, ec, ecl, *sp, *sep, cep;
- Boolean done= false;
- Boolean isHTMLform= false;
-
- #define FindNextPlus(cp) { \
- for (ep=cp,ecl=*(cp-1),ec=*ep; ec!=0 && !((ec=='.' || ec=='+') && ecl<' '); ) \
- {ecl= ec; ec= *(++ep);} }
-
- fIsPlus= isPlus;
- fHasAsk= hasAsk;
- ClearAskReply();
- if (!plus) return;
-
- cp= plus;
- while (*cp!=0) {
- while (*cp!='+' && *cp!=0) cp++;
-
- if (0==Strncasecmp(cp, "+ADMIN:",7)) {
- cp += 7;
- FindNextPlus(cp);
- while (cp < ep) {
- while (*cp <= ' ' && *cp!=0 && cp<ep) cp++; // skip whitespace, newlines
- if (0==Strncasecmp(cp, "Admin:",6)) {
- // Admin: Don Gilbert <archive@bio.indiana.edu>
- MemFree((CharPtr)fAdminEmail);
- sp = cp + 6;
- for (sep= sp; *sep >= ' ' && sep<ep; sep++) ; // skip over other words
- cep= *sep; *sep= 0;
- fAdminEmail= (char*)StrDup(sp);
- *sep= cep;
- }
-
- else if (0==Strncasecmp(cp, "Mod-Date:",9)) {
- sp= StrChr(cp,'<');
- if (sp) {
- // Mod-Date: Thu Feb 4 13:46:47 1993 <19930204134647>
- // convert <19930204134647> to 04Feb93
- char sdate[50];
- sp++;
- // save complete date for sorts, etc.
- sep= sp+10; cep= *sep; *sep= 0;
- fDateLong= atol(sp);
- *sep= cep;
-
- sdate[0]= 0;
- sep= sp+6; //day
- strncat(sdate, sep, 2);
-
- sep= sp+6; cep= *sep; *sep= 0;
- long i= atol(sp+4); // month
- *sep= cep;
- if (i<1 || i>12) strncat(sdate, gMonths[12], 3);
- else strncat(sdate, gMonths[i-1], 3);
- strncat( sdate, sp+2, 2); // year
- MemFree((CharPtr)fDate);
- fDate= (char*) StrDup( sdate);
- }
- }
- while (*cp >= ' ' && *cp!=0 && cp<ep) cp++; // skip over other words
- }
- } // +ADMIN
-
- else if (0==Strncasecmp(cp, "+VIEWS:",7)) {
- cp += 7;
- FindNextPlus(cp);
- DeleteViews();
- fViews = new DList();
- while (cp < ep) {
- while (*cp <= ' ' && *cp!=0 && cp<ep) cp++; // skip whitespace, newlines
- if (*cp!=0 && cp<ep) {
- for (sep= cp; *sep >= ' ' && sep<ep; sep++) ; // skip over other words
- cep= *sep; *sep= 0;
- DGopherItemView* giv= new DGopherItemView( cp);
- fViews->InsertLast( giv);
- if (fDataSize==NULL) {
- fSizeLong= atol( (char*) giv->DataSize());
- char snum[50];
- if (fSizeLong) sprintf( snum, "%luk", fSizeLong);
- else strcpy(snum,"<1k");
- fDataSize= (char*) StrDup( snum);
- }
- *sep= cep;
- cp= sep;
- }
- }
- } // +VIEWS
-
- else if (0==Strncasecmp(cp, "+ASKHTML:",9)) {
- // this format is like +ASK except each item has HTML name tag immediately
- // after ask kind: " Choose:name:label\tchoice1\tchoice2"
- // " Ask:name2:label2\tstring"
- cp += 9;
- isHTMLform= true;
- goto HandleAskForm;
- }
-
- else if (0==Strncasecmp(cp, "+ASK:",5)) {
- cp += 5;
- isHTMLform= false;
- HandleAskForm:
- FindNextPlus(cp);
- DeleteAskers();
- fAskers = new DList;
- while (cp < ep) {
- while (*cp <= ' ' && *cp!=0 && cp<ep) cp++; // skip whitespace, newlines
- if (*cp!=0 && cp<ep) {
- for (sep= cp; (*sep>=' ' || *sep== '\t') && sep<ep; sep++) ; // skip over other words
- cep= *sep; *sep= 0;
- DGopherItemAsk* gia= new DGopherItemAsk( cp, isHTMLform);
- if (gia && gia->fKind == kGopherAskUnknown) delete gia;
- else fAskers->InsertLast( gia);
- *sep= cep;
- cp= sep;
- }
- }
- } //+ASK
-
- else if (0==Strncasecmp(cp, "+ABSTRACT:",10)) {
- cp += 10;
- FindNextPlus(cp);
- cep= *ep; *ep= 0;
- if (fAbstract) fAbstract->Install( cp);
- else fAbstract= new DGopherAbstract( cp);
- *ep= cep;
- } //+ABSTRACT
-
- else if (0 == Strncasecmp( cp, "+URL:", 5) ) {
- cp += 5;
- FindNextPlus(cp);
- //if (fURL) MemFree( fURL);
- cep= *ep; *ep= 0;
- #if 0
- if ( DURL::ParseURL( this, cp, ep-cp) ) ;
- #else
- char* saven= StrDup( (char*)this->GetName());
- if ( DURL::ParseURL( this, cp, ep-cp) ) ;
- if (saven && *saven) this->StoreName(saven);
- MemFree(saven);
- #endif
- *ep= cep;
- }
-
- else if (0==Strncasecmp(cp, "+ISMAP",6)) { // dgg addition
- cp += 6;
- FindNextPlus(cp);
- fIsMap= true;
- // having problems w/ other settings !?!?
- // ?? need special map type ?
- fIsPlus= kGopherPlusYes;
- fTransferType= kTransferBinary;
- //fCommand= cNewGopherText; // ???
- } //+ISMAP
-
- else if (0==Strncasecmp(cp, "+MENU:",6)) { // dgg addition
- cp += 6;
- //FindNextPlus(cp);
- Boolean found= false;
- ep= cp;
- ecl= *(cp-1);
- ec= *ep;
- while (!found) {
- ecl= ec;
- ++ep;
- ec= *ep;
- if (ec == 0) found= true;
- else if ((ecl == kCR || ecl == kLF) && (ec == '+' || ec == '.')) found= true;
- }
-
- if (fGoMenuBlock) delete fGoMenuBlock;
- cep= *ep; *ep= 0;
- fGoMenuBlock= new DGoMenuBlock(this, cp);
- *ep= cep;
- } //+MENU
-
- // +MENUSTRING:
- else if (0==Strncasecmp(cp, "+MENUSTRING:",12)) { // dgg addition
- cp += 12;
- while (*cp && *cp <= ' ') cp++;
- if (*cp == '"') {
- cp++; ep= cp;
- while (*ep && *ep != '"') ep++;
- }
- else if (*cp == '\'') {
- cp++; ep= cp;
- while (*ep && *ep != '\'') ep++;
- }
- else {
- ep= cp;
- while (*ep && *ep > ' ') ep++;
- }
- cep= *ep; *ep= 0;
- //if (fMenuString) MemFree(fMenuString);
- //fMenuString= StrDup(cp);
- if (!fDocLink) fDocLink= new DocLink();
- fDocLink->SetString( cp);
- *ep= cep;
-
- // look for skip value
- cp= ep; if (*cp) cp++;
- while (*cp && *cp <= ' ') cp++;
- if (isdigit(*cp))
- fDocLink->SetSkip( atol(cp));
- //fMenuStringSkip= atol( cp);
-
- FindNextPlus(cp);
- }
-
- // +MENULINE: #parag #startchar #endparag #stopchar
- else if (0==Strncasecmp(cp, "+MENULINE:",10)) { // dgg addition
- cp += 10;
- short atpar, atchar, endpar, endchar;
- #if 1
- while (*cp && *cp <= ' ') cp++;
- atpar= atol( cp);
- while (isdigit(*cp)) cp++; while (*cp && *cp <= ' ') cp++;
- atchar= atol( cp);
- while (isdigit(*cp)) cp++; while (*cp && *cp <= ' ') cp++;
- endpar= atol( cp);
- while (isdigit(*cp)) cp++; while (*cp && *cp <= ' ') cp++;
- endchar= atol( cp);
- #else
- // bad, skipping 1st number !!
- sscanf( cp, "%d%d%d%d", &atpar, &atchar, &endpar, &endchar);
- #endif
- if (!fDocLink) fDocLink= new DocLink();
- fDocLink->SetLine( atpar, atchar, endpar, endchar);
- FindNextPlus(cp);
- }
-
- // +MENURECT: #left #top #right #bottom
- else if (0==Strncasecmp(cp, "+MENURECT:",10)) { // dgg addition
- short left, top, right, bottom;
- Nlm_RecT r;
- cp += 10;
- #if 1
- while (*cp && *cp <= ' ') cp++;
- left= atol( cp);
- while (isdigit(*cp)) cp++; while (*cp && *cp <= ' ') cp++;
- top= atol( cp);
- while (isdigit(*cp)) cp++; while (*cp && *cp <= ' ') cp++;
- right= atol( cp);
- while (isdigit(*cp)) cp++; while (*cp && *cp <= ' ') cp++;
- bottom= atol( cp);
- #else
- // bad, skipping 1st number !!
- sscanf( cp, "%d %d %d %d ", &left, &top, &right, &bottom);
- #endif
- Nlm_LoadRect( &r, left, top, right, bottom);
- if (!fDocLink) fDocLink= new DocLink();
- fDocLink->SetRect(r);
- FindNextPlus(cp);
- }
-
- // +MENULINERECT: #parag #startchar #left #top #right #bottom
- else if (0==Strncasecmp(cp, "+MENULINERECT:",14)) { // dgg addition
- short atpar, atchar, left, top, right, bottom;
- Nlm_RecT r;
- cp += 14;
- #if 1
- while (*cp && *cp <= ' ') cp++;
- atpar= atol( cp);
- while (isdigit(*cp)) cp++; while (*cp && *cp <= ' ') cp++;
- atchar= atol( cp);
- while (isdigit(*cp)) cp++; while (*cp && *cp <= ' ') cp++;
- left= atol( cp);
- while (isdigit(*cp)) cp++; while (*cp && *cp <= ' ') cp++;
- top= atol( cp);
- while (isdigit(*cp)) cp++; while (*cp && *cp <= ' ') cp++;
- right= atol( cp);
- while (isdigit(*cp)) cp++; while (*cp && *cp <= ' ') cp++;
- bottom= atol( cp);
- #else
- // bad, skipping 1st number !!
- sscanf( cp, "%d %d %d %d %d %d ",
- &atpar, &atchar, &left, &top, &right, &bottom);
- #endif
- Nlm_LoadRect( &r, left, top, right, bottom);
- if (!fDocLink) fDocLink= new DocLink();
- fDocLink->SetLineRect(r, atpar, atchar);
- FindNextPlus(cp);
- }
-
- else if (0==Strncasecmp(cp, "+QUERYSTRING:",13)) { // dgg addition
- cp += 13;
- while (*cp && *cp <= ' ') cp++;
- if (*cp == '"') {
- cp++; ep= cp;
- while (*ep && *ep != '"') ep++;
- }
- else if (*cp == '\'') {
- cp++; ep= cp;
- while (*ep && *ep != '\'') ep++;
- }
- else {
- ep= cp;
- while (*ep && *ep > ' ') ep++;
- }
- cep= *ep; *ep= 0;
- if (fQueryGiven) MemFree(fQueryGiven);
- fQueryGiven= StrDup(cp);
- *ep= cep;
- FindNextPlus(cp);
- }
-
- else if (0==Strncasecmp(cp, "+INFO:",6)) {
- cp += 6;
- // this probably means we messed up packaging plus data for this call
- // ?? should we exit/fail ??
- FindNextPlus(cp);
- } //+INFO
-
- else {
- cp++;
- FindNextPlus(cp);
- } // +OTHER +COMMENT
-
- cp= ep;
- }
-
- #undef FindNextPlus
- }
-
-
- void DGopher::SetLink( char ctype, const char* link)
- {
- // link data expected is pointer to standard gopher info line:
- // 0Title<tab>path<tab>host<tab>port<tab>plus...etc...<null | cr-lf>
- char *cp, *cp0;
-
- DeleteLink(true); // clean out any old link info
-
- fLinkLen= StrLen( link) + 1;
- fLink = (char*) MemDup( (void*)link, fLinkLen);
- cp= cp0= fLink;
- fType= ctype; //= *cp; -- we may be overriding link type
- fItitle= 1; // title always starts at 2nd char in link
- cp= StringChr(cp, '\t'); if (cp) { *cp++= 0; fIpath= cp-cp0; } else fIpath= 0;
- cp= StringChr(cp, '\t'); if (cp) { *cp++= 0; fIhost= cp-cp0; } else fIhost= 0;
- cp= StringChr(cp, '\t'); if (cp) { *cp++= 0; fIport= cp-cp0; } else fIport= 0;
- cp= StringChr(cp, '\t'); if (cp) { *cp++= 0; fIplus= cp-cp0; } else fIplus= 0;
-
- fIsLocal= ( fIhost==0
- || StrICmp(fLink+fIhost,kLocalhost) == 0
- || StrICmp(fLink+fIhost,gEmptyString) == 0 );
-
- if (fIport) fPort= (short)atol( cp0 + fIport); else fPort= kGopherport; // ???
-
- // look for Date+Size in title as
- // "File listing [14Apr92, 58kb]" is an example
- cp= cp0 + fItitle;
- char *dp= StringRChr(cp, ']');
- if (dp) {
- char *sz= dp-3;
- if (isdigit(*sz) && sz[1] == 'k' && sz[2] == 'b') {
- char *db= StrRChr(cp, '[');
- if (db && db < dp) {
- char *te= db-1; // terminate title
- while (te > cp0 && isspace(*te)) te--;
- *(te+1)= 0;
- db++; //*db++= 0;
- fIdate= db - cp0;
- while (isdigit(*sz)) sz--;
- fIsize= sz+1 - cp0;
- while (db<sz && *db!=',') db++;
- *db= 0; // terminate date
- *dp= 0; // terminate size
- if (!fDateLong) {
- long yr = atol(cp0+fIdate+5);
- long day= atol(cp0+fIdate);
- long mon= 0;
- while (mon<12 && strncmp(gMonths[mon], cp0+fIdate+2, 3) != 0) mon++;
- fDateLong= 1900000000 + yr * 1000000 + mon * 10000
- + day * 100;
- }
- if (!fSizeLong) {
- fSizeLong= atol(cp0 + fIsize);
- char snum[50];
- if (fSizeLong) sprintf( snum, "%luk", fSizeLong);
- else strcpy(snum,"<1k");
- if (fDataSize) MemFree(fDataSize);
- fDataSize= (char*) StrDup( snum);
- }
- }
- }
- }
- }
-
-
-
-
-
- void DGopher::ToText( CharPtr& h, short indent)
- {
-
- if (TRUE) { // if (fIsPlus)
- char quote, *bufp, *buf, *plus;
- // RISKY having buf at fixed maxlen!, we need better way than sprintf(fixedbuf,...) !!
- long len= MAX( fLinkLen+1, 2048);
- buf = (char*)MemNew(len);
- if (indent<0) indent= 0;
- if (indent) MemFill( buf, ' ', indent);
- bufp= buf+indent;
-
- if (fIsPlus) plus= "\t+"; else plus= "";
- sprintf( bufp, "+INFO: %c%s\t%s\t%s\t%d%s\n",
- fType, (char*) GetName(), (char*) GetPath(), (char*) GetHost(), fPort, plus);
- StrExtendCat( &h, buf);
-
- if (fURL && fProtocol != kGopherprot) {
- //if (StrChr(fURL, '"')) quote= '\''; else quote= '"';
- quote= ' ';
- sprintf( bufp, "+URL: %c%s%c\n", quote,fURL,quote);
- StrExtendCat( &h, buf);
- }
-
- // must store +MENU, +MENUSTRING, +QUERYSTRING and possibly other G+ block info
- // do we care to save +ADMIN, +VIEWS, +ASK, ... ???
-
- if (HasDocLink()) {
- short atparag, atchar;
- switch ( fDocLink->Kind()) {
-
- case DocLink::kNoLink:
- break;
-
- case DocLink::kLine: {
- short endparag, endchar;
- fDocLink->GetLine( atparag, atchar, endparag, endchar);
- sprintf( bufp, "+MENULINE: %d %d %d %d\n",
- atparag, atchar, endparag, endchar);
- StrExtendCat( &h, buf);
- }
- break;
-
- case DocLink::kLineRect: {
- Nlm_RecT r;
- fDocLink->GetLineRect( r, atparag, atchar);
- sprintf( bufp, "+MENULINERECT: %d %d %d %d %d %d\n",
- atparag, atchar, r.left, r.top, r.right, r.bottom);
- StrExtendCat( &h, buf);
- }
- break;
-
- case DocLink::kRect: {
- Nlm_RecT r;
- fDocLink->GetRect( r);
- sprintf( bufp, "+MENURECT: %d %d %d %d\n",
- r.left, r.top, r.right, r.bottom);
- StrExtendCat( &h, buf);
- }
- break;
-
- case DocLink::kString: {
- short skipval = 0;
- char* links= fDocLink->GetString( skipval);
- if (StrChr(links, '"')) quote= '\''; else quote= '"';
- if (skipval)
- sprintf( bufp, "+MENUSTRING: %c%s%c %d\n", quote, links, quote, skipval);
- else
- sprintf( bufp, "+MENUSTRING: %c%s%c\n", quote,links,quote);
- StrExtendCat( &h, buf);
- }
- break;
-
- }
-
- }
-
- if (fQueryGiven) {
- if (StrChr(fQueryGiven, '"')) quote= '\'';
- else quote= '"';
- sprintf( bufp, "+QUERYSTRING: %c%s%c\n", quote,fQueryGiven,quote);
- StrExtendCat( &h, buf);
- }
-
- if (fGoMenuBlock) {
- // ...a bit of recursion...
- char* menutext= fGoMenuBlock->fGolist->WriteLinks(indent+1);
- sprintf(bufp, "+MENU:\n");
- StrExtendCat( &h, buf);
- StrExtendCat( &h, menutext);
- MemFree( menutext);
- }
-
- MemFree(buf);
- }
- else {
- char *buf = (char*)MemNew(fLinkLen+1);
- sprintf( buf, "%c%s\t%s\t%s\t%d\n",
- fType, (char*) GetName(), (char*) GetPath(), (char*) GetHost(), fPort);
- StrExtendCat( &h, buf);
- MemFree(buf);
- }
- }
-
-
- void DGopher::ToServerText( CharPtr& h, short itemNum)
- {
- long maxlen= 7 * 6 + fLinkLen + 600; // is this safely more than we need?
- char *buf= new char[ maxlen];
- char *cp= buf;
- char quote, cplus = (fIsPlus == kGopherPlusYes) ? '+' : ' ';
- char* stmp;
-
- sprintf( cp, "Name=%s%s", (char*) GetName(),LineEnd); cp += strlen(cp);
- if (itemNum) { sprintf( cp, "Numb=%d%s", itemNum,LineEnd); cp += strlen(cp); }
- sprintf( cp, "Type=%c%c%s", fType, cplus,LineEnd); cp += strlen(cp);
- sprintf( cp, "Host=%s%s", (char*) GetHost(),LineEnd); cp += strlen(cp);
- sprintf( cp, "Port=%d%s", fPort,LineEnd); cp += strlen(cp);
- sprintf( cp, "Path=%s%s", (char*) GetPath(),LineEnd); cp += strlen(cp);
- StrExtendCat( &h, buf);
-
- if (fAdminEmail) {
- sprintf( buf, "Admin=%s%s", fAdminEmail,LineEnd);
- StrExtendCat( &h, buf);
- }
- stmp= (char*)GetDate();
- if (stmp && *stmp) {
- sprintf(buf, "#+Mod-Date:%s%s", stmp,LineEnd);
- StrExtendCat( &h, buf);
- }
-
- if (fURL) {
- //if (StrChr(fURL, '"')) quote= '\''; else quote= '"';
- quote= ' ';
- sprintf( buf, "+URL: %c%s%c\n", quote,fURL,quote);
- StrExtendCat( &h, buf);
- }
-
- #if 0
- if (fIsPlus == kGopherPlusYes) {
- sprintf( buf, "#+Views:%s",LineEnd);
- StrExtendCat( &h, buf);
- CArrayIterator iter( fViews);
- void* iview;
- for (iview = iter.First(); iter.More(); iview = iter.Next()) {
- stmp= (*(DGopherItemView**) iview)->ViewVal();
- sprintf( buf, "# %s%s", (char*)stmp,LineEnd);
- StrExtendCat( &h, buf);
- }
- }
- #endif
-
- sprintf( buf, "#%s",LineEnd);
- StrExtendCat( &h, buf);
- delete[] buf;
- }
-
-
-
- void DGopher::ToPrettyText( CharPtr& h, short /*itemNum*/,
- Boolean showDate, Boolean showSize, Boolean showKind, Boolean showPath,
- Boolean showHost, Boolean showPort, Boolean showAdmin)
- {
- char* stmp;
- long maxlen= 8 * 6 + fLinkLen + 600; // is this safely more than we need?
- char *buf= new char[ maxlen];
- char *cp= buf;
- char cplus = (fIsPlus == kGopherPlusYes) ? '+' : ' ';
-
- #define SprintIfReal(WHAT) \
- if (stmp && *stmp) sprintf( cp, "\t%s", stmp); else sprintf( cp, "\t"); \
- cp += strlen(cp);
-
- stmp= (char*)GetName(); sprintf( cp, "%s", stmp); cp += strlen(cp);
- if (showDate) { stmp= (char*)GetDate(); SprintIfReal("Date"); }
- if (showSize) { stmp= (char*)GetDataSize(); SprintIfReal("Size"); }
- if (showKind) { sprintf( cp, "\t%c%c", fType, cplus); cp += strlen(cp); }
- if (showPath) { stmp= (char*)GetPath(); SprintIfReal("Path"); }
- if (showHost) { stmp= (char*)GetHost(); SprintIfReal("Host"); }
- if (showPort) { sprintf( cp, "\t%d", fPort); cp += strlen(cp); }
- if (showAdmin && fAdminEmail) { stmp= fAdminEmail; SprintIfReal("Admin"); }
- sprintf( cp, "%s",LineEnd); cp += strlen(cp);
- StrExtendCat( &h, buf);
-
- delete[] buf;
- }
-
- void DGopher::StoreName(char* aStr)
- {
- long len= 100 + fLinkLen + StrLen(aStr);
- char *link = (char*) MemNew(len);
- char cplus = (fIsPlus == kGopherPlusYes) ? '+' : ' ';
- sprintf( link, "%c%s\t%s\t%s\t%d\t%c",
- fType, aStr/*(char*) GetName()*/, (char*) GetPath(), (char*) GetHost(), fPort, cplus);
- SetLink( fType, link);
- MemFree( link);
- }
-
- void DGopher::StorePath(char* aStr)
- {
- long len= 100 + fLinkLen + StrLen(aStr);
- char *link = (char*) MemNew(len);
- char cplus = (fIsPlus == kGopherPlusYes) ? '+' : ' ';
- sprintf( link, "%c%s\t%s\t%s\t%d\t%c",
- fType, (char*) GetName(), aStr/*(char*) GetPath()*/, (char*) GetHost(), fPort, cplus);
-
- SetLink( fType, link);
- MemFree( link);
- }
-
- void DGopher::StoreHost(char* aStr)
- {
- long len= 100 + fLinkLen + StrLen(aStr);
- char *link = (char*) MemNew(len);
- char cplus = (fIsPlus == kGopherPlusYes) ? '+' : ' ';
- if (!aStr || !*aStr || StrICmp(aStr,gEmptyString) == 0)
- aStr= (char*)kLocalhost;
- sprintf( link, "%c%s\t%s\t%s\t%d\t%c",
- fType, (char*) GetName(), (char*) GetPath(), aStr/*(char*) GetHost()*/, fPort, cplus);
- SetLink( fType, link);
- MemFree( link);
- // done in SetLink: fIsLocal= (StrICmp(aStr,kLocalhost) == 0 ); // fProtocol == kFileprot &&
- }
-
- void DGopher::StorePort(char* aStr)
- {
- long len= 100 + fLinkLen + StrLen(aStr);
- char *link = (char*) MemNew(len);
- char cplus = (fIsPlus == kGopherPlusYes) ? '+' : ' ';
- sprintf( link, "%c%s\t%s\t%s\t%s\t%c",
- fType, (char*) GetName(), (char*) GetPath(), (char*) GetHost(), aStr/*fPort*/, cplus);
- SetLink( fType, link);
- MemFree( link);
- }
-
-
- // static
- short DGopher::StandardPort( short protocol)
- {
- switch (protocol) {
- case kGopherprot: return kGopherport;
- case kHTTPprot : return kHTTPport;
- case kSMTPprot : return kSMTPport;
- case kFileprot : return kFileport;
- case kFTPprot : return kFTPport;
- case kTelnetprot: return kTelnetport;
- case kTN3270prot: return kTN3270port;
- case kWhoisprot : return kWhoisport;
- case kFingerprot: return kFingerport;
- case kPOPprot : return kPOPport;
- case kNNTPprot : return kNNTPport;
- case kWAISprot : return kWAISport;
-
- case kUnsupportedProt: return kUnsupportedPort;
- default:
- case kUnknownProt: return kUnknownPort;
- }
- }
-
- void DGopher::StoreProtocol( short protocol)
- {
- fProtocol= protocol;
- fPort= StandardPort( fProtocol);
- switch (fProtocol) {
-
- case kGopherprot :
- case kHTTPprot :
- case kFTPprot :
- case kFileprot :
- // need to flag if localhost !? -- for all prots ??
- fIsLocal= (StrICmp(GetHost(),kLocalhost) == 0
- || StrICmp(GetHost(),gEmptyString) == 0 );
- break;
-
- // currently unsupported
- case kNNTPprot :
- case kWAISprot :
- case kTelnetprot :
- case kTN3270prot :
- case kUnknownProt:
- case kUnsupportedProt:
- fType= kTypeError; // ??
- break;
- }
- }
-
-
- const char* DGopher::GetProtocol()
- {
- #if 0
- short item= DGopher::GetProtoItem(fProtocol);
- if (item<0) return "unknown://";
- return DGopher::GetProtoName(item);
- #else
- switch (fProtocol) {
- case kNNTPprot : return "news:";
- case kSMTPprot : return "mailto:";
- case kGopherprot : return "gopher://";
- case kHTTPprot : return "http://";
- case kFTPprot : return "ftp://"; // should be same as file:// ??
- case kFileprot : return "file://";
- case kWAISprot : return "wais://";
- case kTelnetprot : return "telnet://";
- case kTN3270prot : return "tn3270://";
-
- case kUnknownProt:
- case kUnsupportedProt:
- default:
- return "unknown://";
- }
- #endif
- }
-
- void DGopher::StoreURL(char* aStr)
- {
- fURL= (char*) MemFree(fURL);
- if (aStr) fURL= StrDup(aStr);
- }
-
- const char* DGopher::GetURL()
- {
- // sprintf( buf, "URL: gopher://%s:%d/%c/%s%s",
- // (char*) GetHost(), fPort, fType, (char*) GetPath(),LineEnd);
- if (!fURL) {
- char cstore[512];
- char* url= StrDup( GetProtocol());
- StrExtendCat( &url, (char*) GetHost());
- if (fPort != StandardPort(fProtocol)) {
- sprintf( cstore, ":%d", fPort);
- StrExtendCat( &url, cstore);
- }
-
- char* epath= DURL::EncodeChars( GetPath());
- switch (fProtocol) {
- case kGopherprot:
- sprintf( cstore, "/%c%s", fType,epath);
- StrExtendCat( &url, cstore);
- break;
-
- case kFileprot:
- if (*epath != '/') {
- StrExtendCat( &url, "/");
- // ?? do some fiddling w/ *path ???
- }
- default:
- StrExtendCat( &url, epath);
- break;
- }
-
- MemFree( epath);
-
- if (fQueryGiven) {
- StrExtendCat( &url, "?");
- StrExtendCat( &url, fQueryGiven);
- }
-
- fURL= url;
- }
- return fURL;
- }
-
-
- void DGopher::StorePlus(char *plus)
- {
- long len= 10 + fLinkLen + 1;
- char *link = (char*) MemNew(len);
- //char cplus = (fIsPlus == kGopherPlusYes) ? '+' : ' ';
- sprintf( link, "%c%s\t%s\t%s\t%d\t%c",
- fType, (char*) GetName(), (char*) GetPath(), (char*) GetHost(), fPort, *plus);
- SetLink( fType, link);
- MemFree( link);
- }
-
- void DGopher::StorePlus(Boolean isplus)
- {
- if (isplus) {
- fIsPlus = kGopherPlusYes;
- StorePlus("+");
- }
- else {
- fIsPlus = kGopherPlusNo;
- StorePlus("");
- }
- }
-
-
-
- Boolean DGopher::Edit(long dialogID)
- {
- Boolean result= false;
-
- DGopherEditWindow *aWind= new DGopherEditWindow(this, dialogID != 0);
- result= aWind->PoseModally();
- delete aWind;
- // aWind handles all of rest -- okay button causes this gopher to be updated
-
- return result;
- }
-
-
- Boolean DGopher::Equals(DGopher* other)
- {
- if (!other) return false;
- else if (fType != other->fType) return false;
- else if (fPort != other->fPort) return false;
- else if (fProtocol != other->fProtocol) return false;
- else if (StringCmp( fLink+fIhost, other->fLink+other->fIhost)) return false;
- else if (StringCmp( fLink+fIpath, other->fLink+other->fIpath)) return false;
- else if (StringCmp( fQueryGiven, other->fQueryGiven)) return false;
- else return true;
- }
-
- Boolean DGopher::operator ==(DGopher* other)
- {
- return Equals(other);
- }
-
-
- void DGopher::SwapPathType(char oldtype, char newtype)
- {
- // this is very risky as protocol says path is opaque to client -- should drop.
- // want it to set binary/text transfer protocol for server
- if (*(fLink+fIpath) == oldtype) *(fLink+fIpath)= newtype;
- }
-
-
- void DGopher::SetOwner( DGopherList* OwnerList)
- {
- fOwnerList= OwnerList;
- if (fOwnerList) fStatusLine= fOwnerList->fStatusLine; // ?? is this only use of fOwnerList?
- gNeedTypeChange= false;
-
- if (gDoSuffix2MacMap && gGopherMap) {
- DGopherMap* mapper;
- mapper= gGopherMap->MatchGopherType( this);
- if (mapper) gNeedTypeChange |= mapper->Map(this);
- mapper= gGopherMap->MatchSuffix( this);
- if (mapper) gNeedTypeChange |= mapper->Map(this);
- }
- }
-
-
-
- const char* DGopher::GetKindName()
- {
- return "Unknown";
- }
-
- const char* DGopher::GetName()
- {
- if (fItitle) return fLink + fItitle;
- else return gEmptyString;
- }
-
- const char* DGopher::GetDate()
- {
- if (fDate) return fDate;
- else if (fIdate) return fLink + fIdate;
- else return gEmptyString;
- }
-
- const char* DGopher::GetDataSize()
- {
- if (fDataSize) return fDataSize;
- else if (fIsize) return fLink + fIsize;
- else return gEmptyString;
- }
-
- const char* DGopher::GetPath()
- {
- if (fIpath) return fLink + fIpath;
- else return gEmptyString;
- }
-
- const char* DGopher::GetHost()
- {
- if (fIhost) return fLink + fIhost;
- else return gEmptyString;
- }
-
- const char* DGopher::GetPort()
- {
- if (fIport) return fLink + fIport;
- else return gEmptyString;
- }
-
- const char* DGopher::GetPlus()
- {
- if (fIplus) return fLink + fIplus;
- else return gEmptyString;
- }
-
-
- const char* DGopher::ShortName()
- {
- static char shorty[33];
- if (fItitle) {
- strncpy(shorty, fLink + fItitle, 32);
- shorty[33]= 0;
- return shorty;
- }
- else return gEmptyString;
- }
-
- void DGopher::ReadALine()
- // this is here for easy subclassing to process line as read thru talker
- {
- char *data = NULL;
-
- if (fIsLocal && fReplyFile) {
- char dline[1024];
- ulong datalen= 1024;
- fReplyFile->ReadLine( dline, datalen);
- if (datalen>0) {
- dline[datalen]= 0;
- if (fInfo == NULL) {
- fInfo= (char*)MemDup(dline, datalen+1);
- fInfoSize= datalen;
- }
- else {
- MemExtendCat( &fInfo, fInfoSize, dline, datalen+1); // +1 for 0
- fInfoSize += datalen;
- }
- }
-
- }
- else if (fTalker && fTalker->ReadALine( NULL, data)) {
- // this changes w/ subclasses...
- if ( data[0] == '.' && data[1] == kCR )
- fTalker->SetEndOfMessage(true);
- if (!fTalker->EndOfMessage()) {
- long datalen= StrLen(data);
- if (fInfo == NULL) {
- fInfo= data;
- fInfoSize= datalen;
- }
- else {
- MemExtendCat( &fInfo, fInfoSize, data, datalen+1); // +1 for 0
- fInfoSize += datalen;
- MemFree( data);
- }
- }
- }
- }
-
-
- Boolean DGopher::EndOfMessage()
- // this is here for easy subclassing to process line as read thru talker
- {
- return fTalker->EndOfMessage();
- }
-
-
-
- void DGopher::ShowMessage(const char* msg)
- {
- if (fStatusLine) fStatusLine->SetTitle( (char*)msg);
- }
-
- void DGopher::ShowProgress()
- {
- char snum[40], buf[128];
- Dgg_LongToStr( fBytesReceived, snum, 0, 40);
- sprintf( buf, "Bytes sent: %s", snum);
- long csec = fConnectTime; // time / 60;
- if (csec > 0) {
- char buf2[128];
- csec= fBytesReceived / csec;
- Dgg_LongToStr( csec, snum, 0, 40);
- sprintf( buf2, "%s, bytes/sec: %s", buf, snum);
- ShowMessage( buf2);
- }
- else
- ShowMessage( buf);
- }
-
-
-
- void DGopher::FinishRead()
- {
- }
-
- const char* DGopher::GetViewChoiceKind()
- {
- if (fViewchoice > 0 && fViews && (fViews->GetSize()>0)) {
- DGopherItemView* giv= (DGopherItemView*) fViews->At(fViewchoice-1);
- if (giv) return giv->Kind();
- }
- return NULL; // or use gGopherMap & fType to return default Kind ??
- }
-
- void DGopher::CheckViewMappers()
- {
- if (fViews) {
- DGopherItemView* giv;
- unsigned short maxrank= 0;
- long i, maxat= 0, nviews= fViews->GetSize();
- char* cp;
- for (i= 0; i<nviews; i++) {
- char * viewkind;
- unsigned short lastrank = 0;
- giv= (DGopherItemView*) fViews->At(i);
- viewkind= (char*)giv->Kind();
- DGopherMap* aMapper= gGopherMap->MatchHandlerKind( lastrank, viewkind);
- if (aMapper) {
- giv->fViewStatus= lastrank;
- if (lastrank > maxrank) { maxrank= lastrank; maxat= i; }
- }
- else
- giv->fViewStatus= DGopherItemView::kUnknownStatus;
- }
- giv= (DGopherItemView*) fViews->At(maxat);
- giv->fViewStatus= DGopherItemView::kMaxStatus;
- if (maxrank>0) fViewchoice= maxat + 1; //???
- }
- }
-
-
-
- #if 0
-
- // LocalGopher.....
-
- types of calls to handle locally:
-
- for all calls
- x-- if StrChr( GetPath(), '/') && !defined(OS_UNIX)
- do filesystem path translation
- x-- must tack on gGopherRoot to top of path ??
-
- for any app call
- x-- add -v view/choice cmdline param ?
-
- if (path == "R123-456-path/to/data")
- x-- handle data file subrange
-
- if (fType == kTypeFolder)
- || StrICmp( viewchoice,"application/gopher-menu") == 0
- || StrICmp( viewchoice,"application/gopher+-menu")==0
- )
- -- do local-filesystem directory to gopher menu translation
- -- some of these types may be to call apps instead (exec+, ?query)
-
- if (fQuery)
- -- assume path is to local executable?
- x-- may be path wais index.{src,dct,inv} instead !?
- ?? can we handle this with call to apps/askwais -d path/to/index ??
- x-- call DChildApp::Launch() w/ fQuery part of cmdline
-
- if (fType == kTypeQuery)
- x-- assume path is to local executable?
- x-- may be path wais index.{src,dct,inv} instead !?
- -- should always have (fQuery) ?
-
- else if (fTypes == othertype)
-
- kTypeFile -- read & display local file
- kTypeBinary
- kTypeSound
- kTypeImage
- kTypeMovie
- kTypeGif
- kTypeHtml
- others -- no special handling
-
- if (StrNICmp( GetPath(), "exec+:", 6)==0)
- x-- assume path is to local executable
- x-- cut cmdline params from exec+:params:/path/to/app
- x-- call DChildApp::Launch()
-
- if (fQueryPlus)
- -- this is typically either "\t+" or "\t$" or "\t!" or esp. fReplyData
- -- this is of low importance?
-
- if (fHaveReply) // for ASK forms,
- x-- see fQueryPlus, but also may have fReplyFile
- x-- assume path is to app, call DChildApp::Launch()
-
- #endif
-
-
-
-
-
- void DGopher::LocalQuery( char* viewchoice)
- {
- enum actions { kDoNothing, kShowFile, kShowFileSection, kShowFolder,
- kLaunchApp, kLaunchWais };
- short action = kDoNothing, kind;
- char * Stdinbuf = NULL, * Stdinfile= NULL;
- char * pathname = StrDup( (char*) GetPath());
- char * cmdline = StrDup("");
- char * shortpath = pathname, * thepath= pathname;
- long rootlen= 0;
- char * cp, * dp;
- long rstart = 0, rend = 0;
- ulong filelen = 0;
-
- fTalker= NULL;
- fBytesExpected= 0; //kReadToClose;
- fBytesReceived= 0;
- fConnectTime= 0;
-
- if (!viewchoice && (fType == kTypeHtml || fProtocol == kHTTPprot)) {
- viewchoice= "text/html";
- }
-
- if (viewchoice) {
- StrExtendCat( &cmdline, " -v ");
- StrExtendCat( &cmdline, viewchoice);
- }
-
- if (StrNICmp( pathname, "exec+:", 6)==0) {
- char * cmds, * ep;
- cmds= pathname+6;
- ep= StrChr( cmds, ':');
- if (ep) {
- *ep++= 0;
- StrExtendCat( &cmdline, " ");
- // ! this is risky, but how else do we handle paths in the cmdline ??
- DFileManager::UnixToLocalPath( cmds);
- StrExtendCat( &cmdline, cmds);
- Nlm_MemMove( pathname, ep, 1+StrLen(ep));
- }
- action= kLaunchApp;
- }
- else if (*pathname == 'R'
- && isdigit(pathname[1])
- && (cp= StrChr(pathname, '-')) != NULL
- && isdigit(cp[1])
- && (dp= StrChr(cp+1, '-')) > cp ) {
- //handle doc subrange paths like 'R851270-852774-:Flybase:genes:genes.txt'
- rstart= atol( pathname+1);
- rend = atol( cp+1);
- dp++;
- Nlm_MemMove( pathname, dp, 1+StrLen(dp));
- action= kShowFileSection;
- }
-
- #if 0
- else if (StrNICmp( pathname, "waissrc:", 6)==0) {
- // ?? kLaunchWais on local wais src ??
- }
- #endif
-
- kind= DFileManager::FileOrFolderExists( pathname);
- if (kind==0) {
- DFileManager::UnixToLocalPath( pathname);
- kind= DFileManager::FileOrFolderExists( pathname);
- if (kind==0) {
- StrPrependCat( &pathname, gLocalGopherRoot);
- rootlen= StrLen(gLocalGopherRoot);
- shortpath= pathname + rootlen;
- thepath= pathname;
- kind= DFileManager::FileOrFolderExists( pathname);
- }
- }
-
- if (kind == DFileManager::kIsFolder) {
- fType= kTypeFolder; // ??
- action= kShowFolder;
- }
-
- if (action == kDoNothing && fType == kTypeQuery && fQuery) {
- if ( DFileManager::FileExists(pathname) )
- action= kLaunchApp;
- else if ( DFileManager::FileExists(shortpath) ) {
- thepath= shortpath;
- action= kLaunchApp;
- }
- else {
- char path2[512];
- StrNCpy( path2, pathname, sizeof(path2));
- StrNCat( path2, ".src", sizeof(path2));
- if (DFileManager::FileExists( path2)) {
- action= kLaunchWais;
- // add default cmdline for AskWais...
- #if 1
- sprintf( path2, " -+i -d %s", pathname);
- #else
- sprintf( path2, " -+i -g %s -d %s", gLocalGopherRoot, pathname);
- #endif
- StrExtendCat( &cmdline, path2);
- }
- else if (DFileManager::FileExists( path2+rootlen)) {
- action= kLaunchWais;
- #if 1
- sprintf( path2, " -+i -d %s", shortpath);
- #else
- sprintf( path2, " -+i -g %s -d %s", gLocalGopherRoot, shortpath);
- #endif
- StrExtendCat( &cmdline, path2);
- }
- }
- }
-
- if (fHasAsk && fHaveReply) {
- action= kLaunchApp;
- if (fQueryPlus) Stdinbuf= fQueryPlus;
- else if (fReplyFile) Stdinfile= (char*) fReplyFile->GetName();
- }
- else if (fQueryPlus) {
- // typically either "\t+" or "\t$" or "\t!"
- }
-
- if (fQuery) {
- *fQuery= ' '; // note: *fQuery == '\t', change to blank for cmdline
- StrExtendCat( &cmdline, " ");
- StrExtendCat( &cmdline, fQuery);
- if (action == kDoNothing) action= kLaunchApp; //?? is just fQuery enough to act this way?
- }
-
- if (action == kDoNothing) switch (fType) {
- case kTypeFile :
- case kTypeBinary:
- case kTypeSound :
- case kTypeImage :
- case kTypeMovie :
- case kTypeGif :
- case kTypeHtml :
- action= kShowFile;
- break;
- case kTypeFolder :
- action= kShowFolder;
- // ?? some subcall if fQueryPlus == $ or + or ! ??
- break;
- }
-
- #if 0
- // ???
- if (action == kDoNothing && ( viewchoice &&
- (StrICmp( viewchoice,"application/gopher-menu")==0
- || StrICmp( viewchoice,"application/gopher+-menu")==0 )
- ) ) {
- action= kShowFolder;
- }
- #endif
-
- if (fQueryPlus && StrCmp(fQueryPlus,"\t!")==0) {
- // drop info calls for now ?
- action= kDoNothing;
- }
-
- switch (action) {
-
- case kShowFileSection: {
- fReplyFile= new DFile( thepath, "rb"); // don't forget "b" binary, or will fail w/ newline translation for bin files !!
- fReplyFile->Open("rb");
- //fReplyFile->GetDataLength(filelen);
- fReplyFile->Seek( rstart);
- fBytesExpected= rend - rstart + 1; // ?? +1 ??
- }
- break;
-
- case kShowFile: {
- fReplyFile= new DFile( thepath, "rb"); // don't forget "b" binary, or will fail w/ newline translation for bin files !!
- fReplyFile->Open("rb");
- fReplyFile->GetDataLength(filelen);
- fBytesExpected= filelen;
- }
- break;
-
- case kShowFolder: {
- #if 0
- //debug
- #include <DApplication.h>
- char* stdoutfile= StrDup("Gopup.localfolder");
- StrPrependCat( &stdoutfile,
- (char*)DFileManager::PathOnlyFromPath( gApplication->Pathname()));
- fReplyFile= new DFile(stdoutfile);
- #else
- fReplyFile= new DTempFile(); // disk file will be removed on delete
- #endif
- fReplyFile->Open("w");
- DGopherList::LocalFolder2GopherList( fReplyFile, thepath);
- fReplyFile->Open("r");
- fReplyFile->GetDataLength(filelen);
- fBytesExpected= filelen;
- }
- break;
-
- case kLaunchApp: {
- DChildApp* child= new DChildApp( thepath, cmdline, true, Stdinfile, true);
- if (Stdinbuf)
- child->AddInputBuffer( DChildFile::kStdin, Stdinbuf, StrLen(Stdinbuf));
- if (!child->Launch())
- Message(MSG_OK, "Failed to launch %s with '%s'", thepath, cmdline);
- }
- break;
-
- case kLaunchWais: {
- if (DFileManager::FileExists( gAskWaisPath))
- thepath= gAskWaisPath;
- else {
- MemFree( pathname);
- pathname= StrDup( gLocalGopherRoot);
- StrExtendCat( &pathname, gAskWaisPath );
- thepath= pathname;
- }
- #if 0
- // debugging
- #include <DApplication.h>
- char* stdoutfile= StrDup("Gopup.stdout");
- StrPrependCat( &stdoutfile,
- (char*)DFileManager::PathOnlyFromPath( gApplication->Pathname()));
- DChildApp* child= new DChildApp( thepath, cmdline, false, NULL, true);
- DChildFile* cfile= new DChildFile( stdoutfile, DChildFile::kStdout,
- DChildFile::kDontDelete, DChildFile::kOpenText, "w");
- child->AddFile(cfile);
- MemFree(stdoutfile);
- #else
- DChildApp* child= new DChildApp( thepath, cmdline, true, NULL, true);
- #endif
- if (!child->Launch())
- Message(MSG_OK, "Failed to launch %s with '%s'", thepath, cmdline);
- }
- break;
-
- case kDoNothing:
- default:
- fBytesExpected= 0;
- break;
- }
-
- fQueryPlus= NULL; // set to zero after each call?
- fQuery= NULL;
-
- MemFree( pathname);
- MemFree( cmdline);
- }
-
-
-
-
- void DGopher::OpenQuery()
- {
- char* viewchoiceptr = NULL;
- char viewchoicestore[256];
-
- if (fViewchoice > 0)
- if (fViews && fViews->GetSize()>1) {
- DGopherItemView* giv= (DGopherItemView*) fViews->At(fViewchoice-1);
- if (giv) {
- strcpy( viewchoicestore, giv->ViewRequest());
- viewchoiceptr= viewchoicestore;
- if (fQueryPlus && (0 == StrCmp(fQueryPlus,"\t+") || 0 == StrCmp(fQueryPlus,"\t$")))
- fQueryPlus= NULL; // !! fix bug of sending <tab>+ after <tab>+viewchoice !!
- }
- }
-
- DeleteInfo();
-
- fThreadState= kThreadStarted;
- if (fIsLocal) {
- LocalQuery( viewchoiceptr);
- return;
- }
-
- fTalker= new DGopherTalk();
- switch (fProtocol) {
-
- case kFingerprot:
- case kWhoisprot:
- case kGopherprot:
- fTalker->OpenQuery( fLink+fIhost, fPort, fLink+fIpath, fQuery,
- viewchoiceptr, fQueryPlus, (fHaveReply)?fReplyFile:NULL);
- break;
-
- case kHTTPprot: {
- char * postdata = NULL;
- char * httppath= DURL::EncodeChars( GetPath()); // ?? possible double-encoding?
- StrPrependCat( &httppath, "GET ");
- if (fQuery) {
- *fQuery= '?'; // note: *fQuery == '\t', change to '?' for http
- StrExtendCat( &httppath, fQuery);
- }
- if (fHaveReply) {
- Boolean isHTMLPostForm= (fHasAsk == 5);
- //Boolean isHTMLForm= (fHasAsk == 3 || fHasAsk == 5);
- //fQueryPlus= fReplyData; << this is set in ReadTask
- if (isHTMLPostForm) {
- postdata= fReplyData;
- }
- else { // GET form
- StrExtendCat( &httppath, "?");
- StrExtendCat( &httppath, fReplyData);
- }
- }
-
- fTalker->OpenQuery( fLink+fIhost, fPort, httppath, NULL,
- NULL, postdata, NULL);
- MemFree(httppath);
- }
- break;
-
-
- case kFTPprot: // file:///path:to:file
- case kFileprot:
- //?? kCSOprot:
- case kWAISprot:
- case kTelnetprot:
- case kTN3270prot:
- case kPOPprot:
- case kNNTPprot:
- case kSMTPprot:
- default:
- break;
-
- }
- fQueryPlus= NULL; // set to zero after each call?
- fQuery= NULL;
- fBytesExpected= kReadToClose;
- fBytesReceived= 0;
- fConnectTime= 0;
-
- // If this is gopher+ server, then it will send first line as one of these
- // which we must eat here...
- // +12345<crlf> number of bytes of data
- // +-1<crlf> data to dot-cr-lf
- // +-2<crlf> data to close-of-connection
-
- //if (fIsPlus != kGopherPlusNo) // << this is bad -- do w/o and trust checks of +##, --1 to work
- if (fProtocol == kGopherprot)
- {
- char* aLine= fTalker->RecvLine();
- if (aLine) {
-
- if (*aLine == '+' && (strlen(aLine) < 20 || fIsPlus == kGopherPlusYes)) {
- fBytesExpected = atol( aLine+1);
- DeleteInfo(); // zero it...
- // bug in kTCPStopAtdotcrlf, switch it to kTCPStopAtclose for now...
- if (fBytesExpected == kReadToDotCRLF) fBytesExpected= kReadToClose;
- else if (fBytesExpected > 0) fTransferType= kTransferBinary; //?? always?
- MemFree( aLine);
- }
-
- else if ( StrStr( aLine,"--1") == aLine) {
- //// error message:
- //--1
- //1 Don Gilbert <Archive@Bio.Indiana.Edu>
- //0- Cannot access that directory
- // 1== Item is not available, 2 == Try again later, 3 == Item has moved...
- char* serror = (char*)gEmptyString;
- char* smail= fTalker->RecvLine();
- if (smail) {
- long len= strlen(smail);
- if (smail[len] == kCR) smail[len]= 0;
- serror= fTalker->RecvLine();
- if (serror) {
- len= strlen(serror);
- if (serror[len] == kCR) serror[len]= 0;
- }
- }
- //CloseQuery();
- DeleteInfo(); // zero it...
- Nlm_Message (MSG_ERROR, "Gopher server error: %s %s", smail, serror);
- fBytesExpected= 0;
- fThreadState= kThreadDoneReading; // need an error state ??
- fTalker->SetEndOfMessage(true);
- MemFree( aLine);
- return;
- }
-
- else {
- //long linelen= StrLen(aLine);
- //MemExtendCat( &fInfo, fInfoSize, aLine, linelen+1);
- MemFree( fInfo);
- // patch for binary data w/ nulls
- fInfoSize= fTalker->NewBytesReceived();
- fInfo= aLine; // aLine is made new in RecvLine()
- if ( MemChr(aLine, 0, fInfoSize-1) != NULL)
- fTransferType= kTransferBinary; //kTransferText;
- }
- }
- }
- }
-
-
- void DGopher::CloseQuery()
- {
- if (fIsLocal) {
- if (fReplyFile) delete fReplyFile;
- fReplyFile= NULL;
- }
- else if (fTalker) {
- fBytesReceived= fTalker->TotalBytesReceived();
- fConnectTime= fTalker->ConnectTime();
- delete fTalker;
- }
- ClearAskReply();
- fTalker= NULL;
- fThreadState= kThreadDoneReading;
- }
-
-
- void DGopher::ReadAChunk( long maxchunk)
- {
- //fThreadState= kThreadStarted;
- if (fIsLocal && fReplyFile) {
- char* data;
- ulong datalen;
-
- if (maxchunk <= 0 || maxchunk > 32000) maxchunk = 32000;
- data = (char*)MemNew( maxchunk+1);
- datalen= MIN( fBytesExpected - fBytesReceived, maxchunk);
- fReplyFile->ReadData(data, datalen);
- if (datalen>0) {
- data[datalen]= 0;
- if (fInfo == NULL || fInfoSize == 0) {
- if (fInfo) MemFree( fInfo);
- fInfo= data; data= NULL; //fInfo= (char*) MemDup(data, datalen+1);
- fInfoSize= datalen;
- }
- else {
- MemExtendCat( &fInfo, fInfoSize, data, datalen+1); // +1 for 0
- fInfoSize += datalen;
- }
- fBytesReceived += datalen;
- }
- MemFree( data);
- if (fReplyFile->EndOfFile() || datalen<maxchunk)
- fThreadState= kThreadDoneReading;
- }
- else if (fTalker) {
- fInfo= fTalker->ReadWithChecks(fInfoSize, fBytesExpected, (fTransferType == kTransferText),
- maxchunk, fInfo);
- }
- //fThreadState= kThreadDataOld;
- }
-
-
- void DGopher::ReadTask()
- {
- fThreadState= kThreadNotStarted; // ! need to reset this somewhere for used gophers
- if (fHasAsk && fHaveReply) { // && fThreadState == kThreadNotStarted
- fQueryPlus= fReplyData;
- }
- OpenQuery();
- if (fThreadState == kThreadDoneReading) return;
- DTask* readTask= newTask(cRead, kGopherTask);
- readTask->SetRepeat(true);
- PostTask(readTask);
- }
-
- void DGopher::InfoTask()
- {
- fThreadState= kThreadNotStarted; // ! need to reset this somewhere for used gophers
- fQueryPlus= "\t!";
- DGopher::OpenQuery(); // bypass class overrides of OpenQuery, which set fQueryPlus !!
- if (fThreadState == kThreadDoneReading) return;
- DTask* aTask= newTask(cInfo, kGopherTask);
- aTask->SetRepeat(true);
- PostTask(aTask);
- }
-
- Boolean DGopher::IsMyTask(DTask* theTask)
- {
- if (theTask->fKind == kGopherTask) {
- ProcessTask( theTask);
- return true;
- }
- else
- return DTaskMaster::IsMyTask(theTask);
- }
-
- void DGopher::ProcessTask(DTask* theTask)
- {
- Boolean more;
- if (theTask->fNumber == cRead) {
- if (fIsLocal)
- more= (fReplyFile && !fReplyFile->EndOfFile()
- && (fBytesExpected - fBytesReceived)>0);
- else
- more= (fTalker && !fTalker->EndOfMessage());
- if (more)
- ReadAChunk(kReadMaxbuf1);
- else {
- theTask->SetRepeat(false);
- FinishRead();
- CloseQuery();
- }
- }
-
- else if (theTask->fNumber == cInfo) {
- if (fIsLocal)
- more= false;
- else
- more= (fTalker && !fTalker->EndOfMessage());
- if (more)
- ReadAChunk(kReadMaxbuf1);
- else {
- theTask->SetRepeat(false);
- FinishRead();
- CloseQuery();
-
- if (fInfo && fInfoSize > 0) {
- if (*fInfo == '+') fIsPlus = kGopherPlusYes;
- else fIsPlus= kGopherPlusNo;
- }
- SetPlusInfo( fIsPlus, fHasAsk, fInfo); // is fInfo safe for use? seems okay
-
- char *info= (char*) MemGet(1,true);
- this->ToServerText( info, 0);
-
- if (fIsPlus == kGopherPlusYes) {
- // tack on all but first +INFO: line
- char *cp, *ep;
- char endbuf[6];
- StrNCpy( endbuf, LineEnd, 4);
- StrCat( endbuf, "#");
- cp = StrChr(fInfo,*LineEnd);
- while (cp) {
- cp++;
- ep= StrChr( cp, *LineEnd);
- if (ep) *ep= 0;
- StrExtendCat( &info, endbuf);
- StrExtendCat( &info, cp);
- cp= ep; if (cp) cp += LineEndSize;
- }
- StrExtendCat( &info, LineEnd);
- }
-
- MemFree( fInfo);
- fInfo= info;
- fInfoSize= StrLen(info);
- fThreadState= kThreadDoneReading;
- }
- }
- }
-
-
-
-
-
-
-
- short DGopher::CommandResult()
- {
- // ?? mapping of command due to mapping of these values ?? see CGopherMap
- return fCommand;
- }
-
-
- void DGopher::SetAskReply( CharPtr data, DFile* replyFile)
- {
- if (fHasAsk && (data || replyFile)) {
- fHaveReply= true;
- fReplyData= data;
- fReplyFile= replyFile;
- }
- }
-
- void DGopher::ClearAskReply()
- {
- if (fReplyData) {
- fReplyData= (char*) MemFree( fReplyData);
- }
- //fReplyFile= (DFile*) FreeIfObject( fReplyFile); !!NO, leave this to creator of DFile !
- fReplyFile= NULL;
- fHaveReply= false;
- }
-
-
-
- short DGopher::ThreadProgress(short /*update*/)
- {
- if (fTalker) {
- fBytesReceived= fTalker->TotalBytesReceived();
- fConnectTime= fTalker->ConnectTime();
- }
- return fThreadState;
- }
-
-
- short DGopher::ItemForm(short viewchoice)
- {
- // we don't want to repeat mapping here and in DoIt() !!
- if (fViews && (fViews->GetSize()>0) && gGopherMap) {
- if (viewchoice<0) fViewchoice= 0; else fViewchoice= viewchoice;
- DGopherMap* mapper= gGopherMap->MatchHandlerKind( this);
- if (mapper) mapper->Map(this);
- }
-
- fViewchoice= viewchoice;
- if (viewchoice == kGetItemInfo)
- return cGopherGetInfo;
- else if (fHasAsk) {
- if (fHaveReply)
- return this->CommandResult();
- else
- return cNewGopherAsk;
- }
- else
- return this->CommandResult();
- }
-
-
- //Local ??
- inline void GoDrawLine( Nlm_RecT& area, char* str)
- {
- if (str) {
- Nlm_DrawString(&area, str, 'l', false);
- #ifndef WIN_MAC
- // XWin/MWin DrawString doesn't set NlmPoint (GetPoint fails to move)
- Nlm_MoveTo( area.left + Nlm_StringWidth(str), area.top);
- #endif
- }
- }
-
- void DGopher::DrawTitle( Nlm_RecT& area)
- {
- ::GoDrawLine( area, fLink + fItitle);
- }
-
- short DGopher::WidthTitle()
- {
- if (fLink) return Nlm_StringWidth( fLink + fItitle);
- else return 0;
- }
-
-
- void DGopher::DrawAbstract( Nlm_RecT& area)
- {
- if (fAbstract) fAbstract->Draw( area);
- }
-
- short DGopher::HeightAbstract()
- {
- if (fAbstract) return fAbstract->Height();
- else return 0;
- }
-
-
- void DGopher::DrawAdmin( Nlm_RecT& area)
- {
- ::GoDrawLine( area, fAdminEmail);
- }
-
- short DGopher::WidthAdmin()
- {
- if (fAdminEmail) return Nlm_StringWidth( fAdminEmail);
- else return 0;
- }
-
-
- void DGopher::DrawPlus( Nlm_RecT& area)
- {
- char* str= NULL;
- if (fIsMap) str= "#";
- else if (fHasAsk) str= "?";
- else if (fIsPlus >= kGopherPlusYes) str= "+";
- ::GoDrawLine( area, str);
- }
-
- short DGopher::WidthPlus()
- {
- return Nlm_StringWidth("?");
- }
-
-
- void DGopher::DrawKind( Nlm_RecT& area)
- {
- ::GoDrawLine( area, (char*) GetKindName());
- }
-
- short DGopher::WidthKind()
- {
- return Nlm_StringWidth( (char*)GetKindName());
- }
-
-
- void DGopher::DrawDate( Nlm_RecT& area)
- {
- char* str= NULL;
- if (fDate) str= fDate;
- else if (fIdate) str= fLink + fIdate;
- ::GoDrawLine( area, str);
- }
-
- short DGopher::WidthDate()
- {
- if (fDate) return Nlm_StringWidth( fDate);
- else if (fIdate) return Nlm_StringWidth( fLink + fIdate);
- else return 0;
- }
-
-
- void DGopher::DrawSize( Nlm_RecT& area)
- {
- char* str= NULL;
- if (fDataSize) ::GoDrawLine( area, fDataSize);
- else if (fIsize) ::GoDrawLine( area, fLink + fIsize);
- }
-
- short DGopher::WidthSize()
- {
- if (fDataSize) return Nlm_StringWidth( fDataSize);
- else if (fIsize) return Nlm_StringWidth( fLink + fIsize);
- else return 0;
- }
-
- void DGopher::DrawPath( Nlm_RecT& area)
- {
- if (fIpath) ::GoDrawLine( area, fLink + fIpath);
- }
-
- short DGopher::WidthPath()
- {
- if (fIpath) return Nlm_StringWidth( fLink + fIpath);
- else return 0;
- }
-
-
- void DGopher::DrawHost( Nlm_RecT& area)
- {
- if (fIhost) ::GoDrawLine( area, fLink + fIhost);
- }
-
- short DGopher::WidthHost()
- {
- if (fIhost) return Nlm_StringWidth( fLink + fIhost);
- else return 0;
- }
-
- void DGopher::DrawPort( Nlm_RecT& area)
- {
- char snum[256];
- Dgg_LongToStr( fPort, snum, 0, 255);
- ::GoDrawLine( area, snum);
- }
-
- short DGopher::WidthPort()
- {
- char snum[256];
- Dgg_LongToStr( fPort, snum, 0, 255);
- return Nlm_StringWidth(snum);
- }
-
- void DGopher::DrawURL( Nlm_RecT& area)
- {
- ::GoDrawLine( area, (char*)GetURL());
- }
-
-
- void DGopher::DrawIconSub( Nlm_RecT& area)
- {
- short idplus;
- DIcon* ico= NULL;
- switch (gIconSize) {
- case 0 : idplus= 20000; break;
- case 1 : idplus= 10000; break;
- case 2 :
- default: idplus= 0; break;
- }
-
- if (gGopherIcons) ico= gGopherIcons->IconById( gGopherIconID + idplus);
- Nlm_InsetRect( &area,1,1); //? do we really want this?
- if (ico) ico->Draw(area);
- }
-
- void DGopher::DrawIcon( Nlm_RecT& area, short size)
- {
- gGopherIconID= kDefaultIcon;
- gIconSize= size;
- DrawIconSub( area);
- }
-
- short DGopher::WidthIcon(short size)
- {
- switch (size) {
- case 0 : return 16; //12 + 4
- case 1 : return 20; //16 + 4
- case 2 : return 36;
- default: return 36;
- }
- }
-
-
-
-
-
-
- struct goTypeRec {
- char kind;
- const char* name;
- Boolean supported:1;
- };
-
- Local goTypeRec gGopherTypes[] = {
- {kTypeFile, "Document", true},
- {kTypeFolder, "Folder", true},
- {kTypeQuery, "Query", true},
- {kTypeBinary, "Binary file", true},
- {kTypeImage, "Image", true},
- {kTypeSound, "Sound", true},
- {kTypeMovie, "Movie", true},
- {kTypeNote, "Note", true},
- {kTypeHtml, "HTML document", true},
- {kMailType, "Mailto", true},
- {kTypeTelnet, "Telnet link", false},
- {kTypeTn3270, "TN3270 link", false},
- #if 0
- {kTypeCSO, "CSO Phonebook", false},
- {kTypeWhois, "Whois Phonebook", false},
- {kTypeBinhex, "Binhex file", false},
- {kTypeUuencode, "Uuencoded file", false},
- #endif
- {kTypeError, "Unknown type", true},
- {0,0}
- };
-
-
- //static
- const char* DGopher::GetTypeName( short listitem)
- {
- if (listitem>=0 && listitem < (sizeof(gGopherTypes) / sizeof(goTypeRec)))
- return gGopherTypes[listitem].name;
- else
- return NULL;
- }
-
- char DGopher::GetTypeVal( short listitem)
- {
- if (listitem>=0 && listitem < (sizeof(gGopherTypes) / sizeof(goTypeRec)))
- return gGopherTypes[listitem].kind;
- else
- return 0;
- }
-
- Boolean DGopher::GetTypeSupport( short listitem)
- {
- if (listitem>=0 && listitem < (sizeof(gGopherTypes) / sizeof(goTypeRec)))
- return gGopherTypes[listitem].supported;
- else
- return 0;
- }
-
- short DGopher::GetTypeItem( char theType)
- {
- short i;
- for (i=0; i < (sizeof(gGopherTypes) / sizeof(goTypeRec)); i++) {
- if (gGopherTypes[i].kind == theType) return i;
- }
- return -1;
- }
-
-
-
- Local goTypeRec gProtoTypes[] = {
- { DGopher::kGopherprot, "gopher://", true },
- { DGopher::kHTTPprot, "http://", true },
- { DGopher::kFileprot, "file://", true },
- { DGopher::kFTPprot, "ftp://", true },
- { DGopher::kSMTPprot,"mailto:", true },
- { DGopher::kWAISprot, "wais://", false },
- { DGopher::kTelnetprot, "telnet://", false },
- { DGopher::kTN3270prot, "tn3270://", false },
- { DGopher::kNNTPprot, "news:", false },
- { DGopher::kFingerprot, "finger:", true },
- { DGopher::kWhoisprot, "whois:", true },
- { DGopher::kUnsupportedProt, "unsupported://", true },
- { DGopher::kUnknownProt, "unknown://", true },
- {0,0}
- };
-
- //static
- const char* DGopher::GetProtoName( short listitem)
- {
- if (listitem>=0 && listitem < (sizeof(gProtoTypes) / sizeof(goTypeRec)))
- return gProtoTypes[listitem].name;
- else
- return NULL;
- }
-
- char DGopher::GetProtoVal( short listitem)
- {
- if (listitem>=0 && listitem < (sizeof(gProtoTypes) / sizeof(goTypeRec)))
- return gProtoTypes[listitem].kind;
- else
- return 0;
- }
-
- Boolean DGopher::GetProtoSupport( short listitem)
- {
- if (listitem>=0 && listitem < (sizeof(gProtoTypes) / sizeof(goTypeRec)))
- return gProtoTypes[listitem].supported;
- else
- return 0;
- }
-
- short DGopher::GetProtoItem( char theProto)
- {
- short i;
- for (i=0; i < ( sizeof(gProtoTypes) / sizeof(goTypeRec)); i++) {
- if (gProtoTypes[i].kind == theProto) return i;
- }
- return -1;
- }
-
-
-
-
-